Micron Document
🎖️GitЯра🎖️

Node / meshtastic / Meshtastic-Android / files / core / service / src / androidHostTest / kotlin / org / meshtastic / core / service / MeshNotificationManagerImplConversationTest.kt

Displaying Raw • Download

core/service/src/androidHostTest/kotlin/org/meshtastic/core/service/MeshNotificationManagerImplConversationTest.kt fix/qr-error-correction (7b45f84f) Text, 12.16 KB

T8b949e/*
* Copyright (c) 2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
Tff7b72package T7ee787org.meshtastic.core.service

Tff7b72import T7ee787android.app.Notification
Tff7b72import T7ee787android.app.NotificationManager
Tff7b72import T7ee787android.content.Context
Tff7b72import T7ee787androidx.test.core.app.ApplicationProvider
Tff7b72import T7ee787androidx.test.ext.junit.runners.AndroidJUnit4
Tff7b72import T7ee787dev.mokkery.MockMode
Tff7b72import T7ee787dev.mokkery.answering.returns
Tff7b72import T7ee787dev.mokkery.every
Tff7b72import T7ee787dev.mokkery.everySuspend
Tff7b72import T7ee787dev.mokkery.matcher.any
Tff7b72import T7ee787dev.mokkery.mock
Tff7b72import T7ee787kotlinx.coroutines.CoroutineScope
Tff7b72import T7ee787kotlinx.coroutines.Dispatchers
Tff7b72import T7ee787kotlinx.coroutines.flow.MutableStateFlow
Tff7b72import T7ee787kotlinx.coroutines.flow.flowOf
Tff7b72import T7ee787kotlinx.coroutines.test.advanceUntilIdle
Tff7b72import T7ee787org.junit.Before
Tff7b72import T7ee787org.junit.Test
Tff7b72import T7ee787org.junit.runner.RunWith
Tff7b72import T7ee787org.meshtastic.core.common.di.asServiceScope
Tff7b72import T7ee787org.meshtastic.core.di.CoroutineDispatchers
Tff7b72import T7ee787org.meshtastic.core.model.ConnectionState
Tff7b72import T7ee787org.meshtastic.core.model.Message
Tff7b72import T7ee787org.meshtastic.core.model.MyNodeInfo
Tff7b72import T7ee787org.meshtastic.core.model.Node
Tff7b72import T7ee787org.meshtastic.core.repository.NodeRepository
Tff7b72import T7ee787org.meshtastic.core.repository.PacketRepository
Tff7b72import T7ee787org.meshtastic.core.repository.RadioConfigRepository
Tff7b72import T7ee787org.meshtastic.core.testing.runUntilSettled
Tff7b72import T7ee787org.meshtastic.core.testing.runWithRenderScope
Tff7b72import T7ee787org.meshtastic.proto.ChannelSet
Tff7b72import T7ee787org.meshtastic.proto.User
Tff7b72import T7ee787org.robolectric.annotation.Config
Tff7b72import T7ee787kotlin.test.assertEquals
Tff7b72import T7ee787kotlin.test.assertNotNull
Tff7b72import T7ee787kotlin.test.assertNull
Tff7b72import T7ee787kotlin.test.assertTrue
Tff7b72import T7ee787org.meshtastic.core.model.Channel Tff7b72as Te6edf3MeshChannel

T8b949e/**
* Behavioral coverage for the conversation-notification pipeline: the historic-vs-new MessagingStyle split, per-type
* (tag, id) namespacing, group-summary alerting/cleanup, and the post-reply refresh flow.
*/
Tf0883e@RunWithTb4b4b4(Te6edf3AndroidJUnit4Tff7b72::Te6edf3classTb4b4b4)
Tf0883e@ConfigTb4b4b4(Te6edf3sdk Tff7b72= Tff7b72[T79c0ff3T79c0ff4Tff7b72]Tb4b4b4)
Tff7b72class T56d364MeshNotificationManagerImplConversationTest Tb4b4b4{

Tff7b72private Tff7b72val Te6edf3contextTb4b4b4: Te6edf3Context Tff7b72= Te6edf3ApplicationProviderTb4b4b4.Te6edf3getApplicationContextTb4b4b4(Tb4b4b4)
Tff7b72private Tff7b72val Te6edf3systemNotificationManager Tff7b72= Te6edf3contextTb4b4b4.Te6edf3getSystemServiceTb4b4b4(Te6edf3NotificationManagerTff7b72::Te6edf3classTb4b4b4.Te6edf3javaTb4b4b4)Tff7b72!!

Tff7b72private Tff7b72val Te6edf3sender Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff7Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!00000007Ta5d6ff"Tb4b4b4, Te6edf3long_name Tff7b72= Ta5d6ff"Ta5d6ffHawk RidgeTa5d6ff"Tb4b4b4, Te6edf3short_name Tff7b72= Ta5d6ff"Ta5d6ffHAWKTa5d6ff"Tb4b4b4)Tb4b4b4)
Tff7b72private Tff7b72val Te6edf3me Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff4T79c0ff2Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!0000002aTa5d6ff"Tb4b4b4, Te6edf3long_name Tff7b72= Ta5d6ff"Ta5d6ffMe NodeTa5d6ff"Tb4b4b4, Te6edf3short_name Tff7b72= Ta5d6ff"Ta5d6ffMETa5d6ff"Tb4b4b4)Tb4b4b4)

Tff7b72private Tff7b72val Te6edf3packetRepositoryTb4b4b4: Te6edf3PacketRepository Tff7b72= Te6edf3mockTb4b4b4(Te6edf3MockModeTb4b4b4.Te6edf3autofillTb4b4b4)
Tff7b72private Tff7b72val Te6edf3nodeRepositoryTb4b4b4: Te6edf3NodeRepository Tff7b72= Te6edf3mockTb4b4b4(Te6edf3MockModeTb4b4b4.Te6edf3autofillTb4b4b4)
Tff7b72private Tff7b72val Te6edf3radioConfigRepositoryTb4b4b4: Te6edf3RadioConfigRepository Tff7b72= Te6edf3mockTb4b4b4(Te6edf3MockModeTb4b4b4.Te6edf3autofillTb4b4b4)

Tff7b72private Tff7b72fun Td2a8ffcreateManagerTb4b4b4(Te6edf3scopeTb4b4b4: Te6edf3CoroutineScopeTb4b4b4) Tff7b72= Te6edf3MeshNotificationManagerImplTb4b4b4(
Te6edf3context Tff7b72= Te6edf3contextTb4b4b4,
Te6edf3packetRepository Tff7b72= Te6edf3lazy Tb4b4b4{ Te6edf3packetRepository Tb4b4b4}Tb4b4b4,
Te6edf3nodeRepository Tff7b72= Te6edf3lazy Tb4b4b4{ Te6edf3nodeRepository Tb4b4b4}Tb4b4b4,
Te6edf3conversationShortcutPublisher Tff7b72=
Te6edf3lazy Tb4b4b4{
Te6edf3ConversationShortcutPublisherTb4b4b4(
Te6edf3contextTb4b4b4,
Te6edf3nodeRepositoryTb4b4b4,
Te6edf3packetRepositoryTb4b4b4,
Te6edf3radioConfigRepositoryTb4b4b4,
Te6edf3CoroutineDispatchersTb4b4b4(
Te6edf3io Tff7b72= Te6edf3DispatchersTb4b4b4.Te6edf3UnconfinedTb4b4b4,
Te6edf3main Tff7b72= Te6edf3DispatchersTb4b4b4.Te6edf3UnconfinedTb4b4b4,
Te6edf3default Tff7b72= Te6edf3DispatchersTb4b4b4.Te6edf3UnconfinedTb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tb4b4b4}Tb4b4b4,
Te6edf3radioConfigRepository Tff7b72= Te6edf3lazy Tb4b4b4{ Te6edf3radioConfigRepository Tb4b4b4}Tb4b4b4,
Te6edf3scope Tff7b72= Te6edf3scopeTb4b4b4.Te6edf3asServiceScopeTb4b4b4(Tb4b4b4)Tb4b4b4,
Tb4b4b4)

Tf0883e@Before
Tff7b72fun Td2a8ffsetUpTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3registerStubMainActivityTb4b4b4(Tb4b4b4)
Te6edf3systemNotificationManagerTb4b4b4.Te6edf3cancelAllTb4b4b4(Tb4b4b4)
Te6edf3every Tb4b4b4{ Te6edf3nodeRepositoryTb4b4b4.Te6edf3ourNodeInfo Tb4b4b4} Te6edf3returns Te6edf3MutableStateFlowTb4b4b4(Te6edf3meTb4b4b4)
Te6edf3every Tb4b4b4{ Te6edf3nodeRepositoryTb4b4b4.Te6edf3myNodeInfo Tb4b4b4} Te6edf3returns Te6edf3MutableStateFlowTff7b72<Te6edf3MyNodeInfo?Tff7b72>Tb4b4b4(Tff7b72nullTb4b4b4)
Te6edf3every Tb4b4b4{ Te6edf3nodeRepositoryTb4b4b4.Te6edf3localStats Tb4b4b4} Te6edf3returns Te6edf3MutableStateFlowTb4b4b4(Te6edf3orgTb4b4b4.Te6edf3meshtasticTb4b4b4.Te6edf3protoTb4b4b4.Te6edf3LocalStatsTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3every Tb4b4b4{ Te6edf3nodeRepositoryTb4b4b4.Te6edf3nodeDBbyNum Tb4b4b4} Te6edf3returns Te6edf3MutableStateFlowTb4b4b4(Te6edf3mapOfTb4b4b4(T79c0ff7 Te6edf3to Te6edf3senderTb4b4b4, T79c0ff4T79c0ff2 Te6edf3to Te6edf3meTb4b4b4)Tb4b4b4)
Te6edf3everySuspend Tb4b4b4{ Te6edf3nodeRepositoryTb4b4b4.Te6edf3getNodeTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns Te6edf3sender
Te6edf3every Tb4b4b4{ Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3channelSetFlow Tb4b4b4} Te6edf3returns
Te6edf3flowOfTb4b4b4(
Te6edf3ChannelSetTb4b4b4(
Te6edf3settings Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3MeshChannelTb4b4b4.Te6edf3defaultTb4b4b4.Te6edf3settingsTb4b4b4)Tb4b4b4,
Te6edf3lora_config Tff7b72= Te6edf3MeshChannelTb4b4b4.Te6edf3defaultTb4b4b4.Te6edf3loraConfigTb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tb4b4b4}

T8b949e/** Newest-first message history, mirroring the repository's ordering. */
Tff7b72private Tff7b72fun Td2a8ffmockHistoryTb4b4b4(Tff7b72vararg Te6edf3messagesTb4b4b4: Te6edf3MessageTb4b4b4) Tb4b4b4{
Te6edf3everySuspend Tb4b4b4{ Te6edf3packetRepositoryTb4b4b4.Te6edf3getMessagesFromTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns Te6edf3flowOfTb4b4b4(Te6edf3messagesTb4b4b4.Te6edf3toListTb4b4b4(Tb4b4b4)Tb4b4b4)
Tb4b4b4}

Tff7b72private Tff7b72fun Td2a8ffmessageTb4b4b4(Te6edf3textTb4b4b4: Tffa657StringTb4b4b4, Te6edf3readTb4b4b4: Tffa657BooleanTb4b4b4, Te6edf3receivedTimeTb4b4b4: Tffa657LongTb4b4b4)Tb4b4b4: Te6edf3Message Tff7b72= Te6edf3MessageTb4b4b4(
Te6edf3uuid Tff7b72= Te6edf3receivedTimeTb4b4b4,
Te6edf3receivedTime Tff7b72= Te6edf3receivedTimeTb4b4b4,
Te6edf3node Tff7b72= Te6edf3senderTb4b4b4,
Te6edf3text Tff7b72= Te6edf3textTb4b4b4,
Te6edf3fromLocal Tff7b72= Tff7b72falseTb4b4b4,
Te6edf3time Tff7b72= Ta5d6ff"Ta5d6ff"Tb4b4b4,
Te6edf3read Tff7b72= Te6edf3readTb4b4b4,
Te6edf3status Tff7b72= Tff7b72nullTb4b4b4,
Te6edf3routingError Tff7b72= T79c0ff0Tb4b4b4,
Te6edf3packetId Tff7b72= Te6edf3receivedTimeTb4b4b4.Te6edf3toIntTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3emojis Tff7b72= Te6edf3emptyListTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3snr Tff7b72= T79c0ff0fTb4b4b4,
Te6edf3rssi Tff7b72= T79c0ff0Tb4b4b4,
Te6edf3hopsAway Tff7b72= T79c0ff0Tb4b4b4,
Te6edf3replyId Tff7b72= Tff7b72nullTb4b4b4,
Tb4b4b4)

Tff7b72private Tff7b72fun Td2a8ffactiveByTagTb4b4b4(Te6edf3tagTb4b4b4: Tffa657StringTb4b4b4) Tff7b72= Te6edf3systemNotificationManagerTb4b4b4.Te6edf3activeNotificationsTb4b4b4.Te6edf3filter Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3tag Tff7b72=Tff7b72= Te6edf3tag Tb4b4b4}

T8b949e/**
* Registers a stub `org.meshtastic.app.MainActivity` with the Robolectric `PackageManager` so that
* `TaskStackBuilder.addNextIntentWithParentStack` can resolve the deep-link host activity, which lives in
* `:androidApp` and is intentionally not on this module's test classpath.
*/
Tff7b72private Tff7b72fun Td2a8ffregisterStubMainActivityTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3componentName Tff7b72= Te6edf3androidTb4b4b4.Te6edf3contentTb4b4b4.Te6edf3ComponentNameTb4b4b4(Te6edf3contextTb4b4b4, Ta5d6ff"Ta5d6fforg.meshtastic.app.MainActivityTa5d6ff"Tb4b4b4)
Tff7b72val Te6edf3activityInfo Tff7b72=
Te6edf3androidTb4b4b4.Te6edf3contentTb4b4b4.Te6edf3pmTb4b4b4.Te6edf3ActivityInfoTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3apply Tb4b4b4{
Te6edf3name Tff7b72= Te6edf3componentNameTb4b4b4.Te6edf3className
Te6edf3packageName Tff7b72= Te6edf3componentNameTb4b4b4.Te6edf3packageName
Te6edf3exported Tff7b72= Tff7b72true
Tb4b4b4}
Te6edf3orgTb4b4b4.Te6edf3robolectricTb4b4b4.Te6edf3ShadowsTb4b4b4.Te6edf3shadowOfTb4b4b4(Te6edf3contextTb4b4b4.Te6edf3packageManagerTb4b4b4)Tb4b4b4.Te6edf3addOrUpdateActivityTb4b4b4(Te6edf3activityInfoTb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`read messages become historic context and unread messages stay alerting`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runWithRenderScope Tb4b4b4{ Te6edf3scope Tff7b72-Tff7b72>
Tff7b72val Te6edf3manager Tff7b72= Te6edf3createManagerTb4b4b4(Te6edf3scopeTb4b4b4)Tb4b4b4.Te6edf3also Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3initChannelsTb4b4b4(Tb4b4b4) Tb4b4b4}
Te6edf3mockHistoryTb4b4b4(
Te6edf3messageTb4b4b4(Ta5d6ff"Ta5d6ffnew unreadTa5d6ff"Tb4b4b4, Te6edf3read Tff7b72= Tff7b72falseTb4b4b4, Te6edf3receivedTime Tff7b72= T79c0ff3Te6edf3_000Tb4b4b4)Tb4b4b4,
Te6edf3messageTb4b4b4(Ta5d6ff"Ta5d6ffolder read 2Ta5d6ff"Tb4b4b4, Te6edf3read Tff7b72= Tff7b72trueTb4b4b4, Te6edf3receivedTime Tff7b72= T79c0ff2Te6edf3_000Tb4b4b4)Tb4b4b4,
Te6edf3messageTb4b4b4(Ta5d6ff"Ta5d6ffolder read 1Ta5d6ff"Tb4b4b4, Te6edf3read Tff7b72= Tff7b72trueTb4b4b4, Te6edf3receivedTime Tff7b72= T79c0ff1Te6edf3_000Tb4b4b4)Tb4b4b4,
Tb4b4b4)

Te6edf3managerTb4b4b4.Te6edf3updateMessageNotificationTb4b4b4(
Ta5d6ff"Ta5d6ff0^allTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffHawk RidgeTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffnew unreadTa5d6ff"Tb4b4b4,
Te6edf3isBroadcast Tff7b72= Tff7b72trueTb4b4b4,
Te6edf3channelName Tff7b72= Ta5d6ff"Ta5d6ffLongFastTa5d6ff"Tb4b4b4,
Tb4b4b4)
Te6edf3advanceUntilIdleTb4b4b4(Tb4b4b4)

Tff7b72val Te6edf3posted Tff7b72= Te6edf3activeByTagTb4b4b4(Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4)Tb4b4b4.Te6edf3singleTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3notification
Tff7b72val Te6edf3alerting Tff7b72= Te6edf3postedTb4b4b4.Te6edf3extrasTb4b4b4.Te6edf3getParcelableArrayTb4b4b4(Te6edf3NotificationTb4b4b4.Te6edf3EXTRA_MESSAGESTb4b4b4)
Tff7b72val Te6edf3historic Tff7b72= Te6edf3postedTb4b4b4.Te6edf3extrasTb4b4b4.Te6edf3getParcelableArrayTb4b4b4(Te6edf3NotificationTb4b4b4.Te6edf3EXTRA_HISTORIC_MESSAGESTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff1Tb4b4b4, Te6edf3alertingTff7b72?.Te6edf3sizeTb4b4b4, Ta5d6ff"Ta5d6ffonly the unread message should be presented as new contentTa5d6ff"Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff2Tb4b4b4, Te6edf3historicTff7b72?.Te6edf3sizeTb4b4b4, Ta5d6ff"Ta5d6ffread context should be carried as historic messagesTa5d6ff"Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Ta5d6ff"Ta5d6ffnew unreadTa5d6ff"Tb4b4b4, Te6edf3postedTb4b4b4.Te6edf3extrasTb4b4b4.Te6edf3getCharSequenceTb4b4b4(Te6edf3NotificationTb4b4b4.Te6edf3EXTRA_TEXTTb4b4b4)Tff7b72?.Te6edf3toStringTb4b4b4(Tb4b4b4)Tb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`group summary alerts via children only and is dropped with the last conversation`Tb4b4b4(Tb4b4b4) Tff7b72=
Te6edf3runWithRenderScope Tb4b4b4{ Te6edf3scope Tff7b72-Tff7b72>
Tff7b72val Te6edf3manager Tff7b72= Te6edf3createManagerTb4b4b4(Te6edf3scopeTb4b4b4)Tb4b4b4.Te6edf3also Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3initChannelsTb4b4b4(Tb4b4b4) Tb4b4b4}
Te6edf3mockHistoryTb4b4b4(Te6edf3messageTb4b4b4(Ta5d6ff"Ta5d6ffhelloTa5d6ff"Tb4b4b4, Te6edf3read Tff7b72= Tff7b72falseTb4b4b4, Te6edf3receivedTime Tff7b72= T79c0ff1Te6edf3_000Tb4b4b4)Tb4b4b4)

Te6edf3managerTb4b4b4.Te6edf3updateMessageNotificationTb4b4b4(
Ta5d6ff"Ta5d6ff0^allTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffHawk RidgeTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffhelloTa5d6ff"Tb4b4b4,
Te6edf3isBroadcast Tff7b72= Tff7b72trueTb4b4b4,
Te6edf3channelName Tff7b72= Ta5d6ff"Ta5d6ffLongFastTa5d6ff"Tb4b4b4,
Tb4b4b4)
Te6edf3advanceUntilIdleTb4b4b4(Tb4b4b4)

Tff7b72val Te6edf3summary Tff7b72= Te6edf3activeByTagTb4b4b4(Ta5d6ff"Ta5d6ffmessage_summaryTa5d6ff"Tb4b4b4)Tb4b4b4.Te6edf3singleTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3notification
Te6edf3assertEqualsTb4b4b4(Te6edf3NotificationTb4b4b4.Te6edf3GROUP_ALERT_CHILDRENTb4b4b4, Te6edf3summaryTb4b4b4.Te6edf3groupAlertBehaviorTb4b4b4)
T8b949e// The summary line is rebuilt from the child's real MessagingStyle, so it carries the actual sender.
Tff7b72val Te6edf3summaryLatest Tff7b72=
Te6edf3androidxTb4b4b4.Te6edf3coreTb4b4b4.Te6edf3appTb4b4b4.Te6edf3NotificationCompatTb4b4b4.Te6edf3MessagingStyleTb4b4b4.Te6edf3extractMessagingStyleFromNotificationTb4b4b4(Te6edf3summaryTb4b4b4)
Tff7b72?.Te6edf3messages
Tff7b72?.Te6edf3lastOrNullTb4b4b4(Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Ta5d6ff"Ta5d6ffhelloTa5d6ff"Tb4b4b4, Te6edf3summaryLatestTff7b72?.Te6edf3textTff7b72?.Te6edf3toStringTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Ta5d6ff"Ta5d6ffHawk RidgeTa5d6ff"Tb4b4b4, Te6edf3summaryLatestTff7b72?.Te6edf3personTff7b72?.Te6edf3nameTff7b72?.Te6edf3toStringTb4b4b4(Tb4b4b4)Tb4b4b4)

Te6edf3managerTb4b4b4.Te6edf3cancelMessageNotificationTb4b4b4(Ta5d6ff"Ta5d6ff0^allTa5d6ff"Tb4b4b4)

Te6edf3assertTrueTb4b4b4(Te6edf3activeByTagTb4b4b4(Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4)Tb4b4b4.Te6edf3isEmptyTb4b4b4(Tb4b4b4)Tb4b4b4, Ta5d6ff"Ta5d6ffconversation should be cancelledTa5d6ff"Tb4b4b4)
Te6edf3assertTrueTb4b4b4(Te6edf3activeByTagTb4b4b4(Ta5d6ff"Ta5d6ffmessage_summaryTa5d6ff"Tb4b4b4)Tb4b4b4.Te6edf3isEmptyTb4b4b4(Tb4b4b4)Tb4b4b4, Ta5d6ff"Ta5d6ffsummary must not outlive the last conversationTa5d6ff"Tb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`notification ids are namespaced per type so a node num cannot clobber the service notification`Tb4b4b4(Tb4b4b4) Tff7b72=
Te6edf3runWithRenderScope Tb4b4b4{ Te6edf3scope Tff7b72-Tff7b72>
Tff7b72val Te6edf3manager Tff7b72= Te6edf3createManagerTb4b4b4(Te6edf3scopeTb4b4b4)Tb4b4b4.Te6edf3also Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3initChannelsTb4b4b4(Tb4b4b4) Tb4b4b4}
T8b949e// SERVICE_NOTIFY_ID is 101; a node whose num is also 101 used to overwrite the foreground notification.
Te6edf3managerTb4b4b4.Te6edf3updateServiceStateNotificationTb4b4b4(Te6edf3ConnectionStateTb4b4b4.Te6edf3ConnectedTb4b4b4, Te6edf3telemetry Tff7b72= Tff7b72nullTb4b4b4)
Te6edf3managerTb4b4b4.Te6edf3showOrUpdateLowBatteryNotificationTb4b4b4(Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff0T79c0ff1Tb4b4b4)Tb4b4b4, Te6edf3isRemote Tff7b72= Tff7b72falseTb4b4b4)
Te6edf3runUntilSettled Tb4b4b4{
Te6edf3systemNotificationManagerTb4b4b4.Te6edf3activeNotificationsTb4b4b4.Te6edf3any Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3id Tff7b72=Tff7b72= T79c0ff1T79c0ff0T79c0ff1 Tff7b72&Tff7b72& Tffa657itTb4b4b4.Te6edf3tag Tff7b72=Tff7b72= Tff7b72null Tb4b4b4} Tff7b72&Tff7b72&
Te6edf3activeByTagTb4b4b4(Ta5d6ff"Ta5d6fflow_batteryTa5d6ff"Tb4b4b4)Tb4b4b4.Te6edf3any Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3id Tff7b72=Tff7b72= T79c0ff1T79c0ff0T79c0ff1 Tb4b4b4}
Tb4b4b4}

Tff7b72val Te6edf3service Tff7b72= Te6edf3systemNotificationManagerTb4b4b4.Te6edf3activeNotificationsTb4b4b4.Te6edf3filter Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3id Tff7b72=Tff7b72= T79c0ff1T79c0ff0T79c0ff1 Tff7b72&Tff7b72& Tffa657itTb4b4b4.Te6edf3tag Tff7b72=Tff7b72= Tff7b72null Tb4b4b4}
Tff7b72val Te6edf3battery Tff7b72= Te6edf3activeByTagTb4b4b4(Ta5d6ff"Ta5d6fflow_batteryTa5d6ff"Tb4b4b4)Tb4b4b4.Te6edf3filter Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3id Tff7b72=Tff7b72= T79c0ff1T79c0ff0T79c0ff1 Tb4b4b4}
Te6edf3assertEqualsTb4b4b4(T79c0ff1Tb4b4b4, Te6edf3serviceTb4b4b4.Te6edf3sizeTb4b4b4, Ta5d6ff"Ta5d6ffservice notification should surviveTa5d6ff"Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff1Tb4b4b4, Te6edf3batteryTb4b4b4.Te6edf3sizeTb4b4b4, Ta5d6ff"Ta5d6fflow-battery notification should coexist under its own tagTa5d6ff"Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff0Te6edf3xFF67EA94Tb4b4b4.Te6edf3toIntTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3serviceTb4b4b4.Te6edf3singleTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3notificationTb4b4b4.Te6edf3colorTb4b4b4, Ta5d6ff"Ta5d6ffbrand accent colorTa5d6ff"Tb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`refreshConversationAfterReply reposts the conversation with the effective channel name`Tb4b4b4(Tb4b4b4) Tff7b72=
Te6edf3runWithRenderScope Tb4b4b4{ Te6edf3scope Tff7b72-Tff7b72>
Tff7b72val Te6edf3manager Tff7b72= Te6edf3createManagerTb4b4b4(Te6edf3scopeTb4b4b4)Tb4b4b4.Te6edf3also Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3initChannelsTb4b4b4(Tb4b4b4) Tb4b4b4}
Te6edf3mockHistoryTb4b4b4(Te6edf3messageTb4b4b4(Ta5d6ff"Ta5d6fforiginalTa5d6ff"Tb4b4b4, Te6edf3read Tff7b72= Tff7b72trueTb4b4b4, Te6edf3receivedTime Tff7b72= T79c0ff1Te6edf3_000Tb4b4b4)Tb4b4b4)

Te6edf3managerTb4b4b4.Te6edf3refreshConversationAfterReplyTb4b4b4(Ta5d6ff"Ta5d6ff0^allTa5d6ff"Tb4b4b4)
Te6edf3advanceUntilIdleTb4b4b4(Tb4b4b4)

Tff7b72val Te6edf3posted Tff7b72= Te6edf3activeByTagTb4b4b4(Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4)Tb4b4b4.Te6edf3singleTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3notification
T8b949e// Empty primary channel resolves to its modem-preset display name, matching the in-app conversation list.
Te6edf3assertEqualsTb4b4b4(Ta5d6ff"Ta5d6ffLongFastTa5d6ff"Tb4b4b4, Te6edf3postedTb4b4b4.Te6edf3extrasTb4b4b4.Te6edf3getCharSequenceTb4b4b4(Te6edf3NotificationTb4b4b4.Te6edf3EXTRA_CONVERSATION_TITLETb4b4b4)Tff7b72?.Te6edf3toStringTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3assertNotNullTb4b4b4(Te6edf3postedTb4b4b4.Te6edf3extrasTb4b4b4.Te6edf3getParcelableArrayTb4b4b4(Te6edf3NotificationTb4b4b4.Te6edf3EXTRA_MESSAGESTb4b4b4)Tb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`refreshConversationAfterReply resolves a dm peer name for the shortcut label`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runWithRenderScope Tb4b4b4{ Te6edf3scope Tff7b72-Tff7b72>
Tff7b72val Te6edf3manager Tff7b72= Te6edf3createManagerTb4b4b4(Te6edf3scopeTb4b4b4)Tb4b4b4.Te6edf3also Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3initChannelsTb4b4b4(Tb4b4b4) Tb4b4b4}
Te6edf3mockHistoryTb4b4b4(Te6edf3messageTb4b4b4(Ta5d6ff"Ta5d6ffdm textTa5d6ff"Tb4b4b4, Te6edf3read Tff7b72= Tff7b72trueTb4b4b4, Te6edf3receivedTime Tff7b72= T79c0ff1Te6edf3_000Tb4b4b4)Tb4b4b4)

Te6edf3managerTb4b4b4.Te6edf3refreshConversationAfterReplyTb4b4b4(Ta5d6ff"Ta5d6ff0!00000007Ta5d6ff"Tb4b4b4)
Te6edf3advanceUntilIdleTb4b4b4(Tb4b4b4)

Tff7b72val Te6edf3posted Tff7b72= Te6edf3activeByTagTb4b4b4(Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4)Tb4b4b4.Te6edf3singleTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3notification
T8b949e// A DM is not a group conversation, so no conversation title is set.
Te6edf3assertNullTb4b4b4(Te6edf3postedTb4b4b4.Te6edf3extrasTb4b4b4.Te6edf3getCharSequenceTb4b4b4(Te6edf3NotificationTb4b4b4.Te6edf3EXTRA_CONVERSATION_TITLETb4b4b4)Tb4b4b4)
T8b949e// The on-demand shortcut published for the notification carries the peer's resolved name.
Tff7b72val Te6edf3shortcut Tff7b72=
Te6edf3contextTb4b4b4.Te6edf3getSystemServiceTb4b4b4(Te6edf3androidTb4b4b4.Te6edf3contentTb4b4b4.Te6edf3pmTb4b4b4.Te6edf3ShortcutManagerTff7b72::Te6edf3classTb4b4b4.Te6edf3javaTb4b4b4)Tff7b72!!Tb4b4b4.Te6edf3dynamicShortcutsTb4b4b4.Te6edf3single Tb4b4b4{
Tffa657itTb4b4b4.Te6edf3id Tff7b72=Tff7b72= Ta5d6ff"Ta5d6ff0!00000007Ta5d6ff"
Tb4b4b4}
Te6edf3assertEqualsTb4b4b4(Ta5d6ff"Ta5d6ffHawk RidgeTa5d6ff"Tb4b4b4, Te6edf3shortcutTb4b4b4.Te6edf3shortLabelTb4b4b4)
Tb4b4b4}
Tb4b4b4}

Served by rngit 1.5.0 - Generated in 0.09s